package com.tensquare.user.service;

import java.util.*;
import java.util.concurrent.TimeUnit;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import util.IdWorker;

import com.tensquare.user.dao.UserDao;
import com.tensquare.user.pojo.User;

/**
 * 服务层
 *
 * @author Administrator
 */
@Service
@Transactional
public class UserService {

    @Autowired
    private UserDao userDao;

    @Autowired
    private IdWorker idWorker;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private BCryptPasswordEncoder encoder;


    /**
     * 注册用户
     * @param code
     * @param user
     */
    public void register(String code, User user) {
        //从redis中取出正确验证码进行校验
        String redisCheckCode = (String) redisTemplate.opsForValue().get("phoneNumber_"+user.getMobile());
        if (StringUtils.isEmpty(redisCheckCode)) {
            throw new RuntimeException("验证码超时");
        }
        if (!redisCheckCode.equals(code)) {
            throw new RuntimeException("验证码错误");
        }

        //补充用户信息
        user.setId(idWorker.nextId()+"");
        user.setFanscount(0);  //粉丝数
        user.setFollowcount(0);  //关注数
        user.setOnline(0L);  //在线时间
        user.setRegdate(new Date());  //在线时间

        //从redis中删除该用户的验证码信息
        redisTemplate.delete("phoneNumber_"+user.getMobile());

        //使用BCryptPasswordEncoder 加密用户密码
        user.setPassword(encoder.encode(user.getPassword()));

        //将用户保存到数据库中
        userDao.save(user);


    }


    /**
     * 用户登录校验
     * @param user
     * @return
     */
    public User login(User user) {
        //1.使用手机号从数据库中查询user对象
        User loginUser = userDao.findByMobile(user.getMobile());
        if (loginUser == null) {
            //查询不到 => 手机号不存在 =>返回null
            return null;
        }
        //2.使用工具类对比密码是否一致
        //参数1:明文密码   参数2:密文密码
        if (!encoder.matches(user.getPassword(),loginUser.getPassword())) {
            //不一致 => 密码错误 => 返回null
            return null;
        }
        //3.返回查询到的user
        return loginUser;
    }


    /**
     * 发送手机验证码
     * 将手机号和验证码发送给RabbitMQ中
     * tensquare_sms中的监听器会从RabbitMQ中获取信息,转发到阿里云
     * 从而实现发送短信的功能
     *
     * @param mobileNumber
     */
    public void sendSms(String mobileNumber) {
        //1.生成手机验证码  生成0 <= ... < 999999
        int num = new Random().nextInt(999999);
        //如果生成的数小于100000 也就是不满6位数时
        if (num < 100000) {
            //让它变为6位数
            num += 100000;
        }
        System.out.println("验证码:"+num);
        //2.将验证码作为消息发送到RabbitMq中
        Map<String,String> map = new HashMap<>();
        map.put("phoneNumber",mobileNumber);
        map.put("checkCode",num+"");
        //以直接模式(Direct) 发送给RabbitMQ中的sms队列    RabbitMQ还有 分列模式(fanout), 主题模式(topic)
        rabbitTemplate.convertAndSend("sms",map);
        //3.将验证码存入redis
        redisTemplate.opsForValue().set("phoneNumber_"+mobileNumber,num+"",5, TimeUnit.MINUTES);
    }

    /**
     * 查询全部列表
     *
     * @return
     */
    public List<User> findAll() {
        return userDao.findAll();
    }

    /**
     * 分页查询
     *
     * @param page
     * @param size
     * @return
     */
    public Page<User> findPage(int page, int size) {
        PageRequest pageRequest = PageRequest.of(page - 1, size);
        return userDao.findAll(pageRequest);
    }


    /**
     * 条件查询
     *
     * @param whereMap
     * @param page
     * @param size
     * @return
     */
    public Page<User> findSearch(Map whereMap, int page, int size) {
        Specification<User> specification = where(whereMap);
        PageRequest pageRequest = PageRequest.of(page - 1, size);
        return userDao.findAll(specification, pageRequest);
    }


    /**
     * 根据ID查询实体
     *
     * @param id
     * @return
     */
    public User findById(String id) {
        return userDao.findById(id).get();
    }

    /**
     * 增加
     *
     * @param user
     */
    public void add(User user) {
        user.setId(idWorker.nextId() + "");
        userDao.save(user);
    }

    /**
     * 修改
     *
     * @param user
     */
    public void update(User user) {
        userDao.save(user);
    }

    /**
     * 删除
     *
     * @param id
     */
    public void deleteById(String id) {
        userDao.deleteById(id);
    }

    /**
     * 动态条件构建
     *
     * @param searchMap
     * @return
     */
    private Specification<User> where(Map searchMap) {

        return new Specification<User>() {

            @Override
            public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                List<Predicate> predicateList = new ArrayList<Predicate>();
                // ID
                if (searchMap.get("id") != null && !"".equals(searchMap.get("id"))) {
                    predicateList.add(cb.like(root.get("id").as(String.class), "%" + (String) searchMap.get("id") + "%"));
                }
                // 手机号码
                if (searchMap.get("mobile") != null && !"".equals(searchMap.get("mobile"))) {
                    predicateList.add(cb.like(root.get("mobile").as(String.class), "%" + (String) searchMap.get("mobile") + "%"));
                }
                // 密码
                if (searchMap.get("password") != null && !"".equals(searchMap.get("password"))) {
                    predicateList.add(cb.like(root.get("password").as(String.class), "%" + (String) searchMap.get("password") + "%"));
                }
                // 昵称
                if (searchMap.get("nickname") != null && !"".equals(searchMap.get("nickname"))) {
                    predicateList.add(cb.like(root.get("nickname").as(String.class), "%" + (String) searchMap.get("nickname") + "%"));
                }
                // 性别
                if (searchMap.get("sex") != null && !"".equals(searchMap.get("sex"))) {
                    predicateList.add(cb.like(root.get("sex").as(String.class), "%" + (String) searchMap.get("sex") + "%"));
                }
                // 头像
                if (searchMap.get("avatar") != null && !"".equals(searchMap.get("avatar"))) {
                    predicateList.add(cb.like(root.get("avatar").as(String.class), "%" + (String) searchMap.get("avatar") + "%"));
                }
                // E-Mail
                if (searchMap.get("email") != null && !"".equals(searchMap.get("email"))) {
                    predicateList.add(cb.like(root.get("email").as(String.class), "%" + (String) searchMap.get("email") + "%"));
                }
                // 兴趣
                if (searchMap.get("interest") != null && !"".equals(searchMap.get("interest"))) {
                    predicateList.add(cb.like(root.get("interest").as(String.class), "%" + (String) searchMap.get("interest") + "%"));
                }
                // 个性
                if (searchMap.get("personality") != null && !"".equals(searchMap.get("personality"))) {
                    predicateList.add(cb.like(root.get("personality").as(String.class), "%" + (String) searchMap.get("personality") + "%"));
                }

                return cb.and(predicateList.toArray(new Predicate[predicateList.size()]));

            }
        };

    }

    /**
     * 修改粉丝数量
     * @param userId
     * @param count
     * @return
     */
    public void changeFansCount(String userId, Integer count) {
        //int i = 1/0;  异常调试
        userDao.changeFansCount(userId,count);
    }
    /**
     * 修改关注数量
     * @param userId
     * @param count
     * @return
     */
    public void changeFollowCount(String userId, Integer count) {
        userDao.changeFollowCount(userId,count);
    }
}
